#include "MutexLock.h"
#include "OSProc.h"
#include <ring.h>


#define NOW	(((_tcb*)(run->content))->pPro)
#define NOWT	(((_tcb*)(run->content)))


#define _KHEAPAPPLY(x)			(Kmalloc((_mch*)&kmemory,x))
#define _KHEAPRELEA(x)			(Kfree((_mch*)&kmemory,x))

#define _KMalloc(x)      (Kmalloc(&kmemory,x))
#define _KFree(x)        (Kfree(&kmemory,x))
extern volatile ring* run;
extern volatile ring* sleep;
extern volatile unsigned int old;
extern volatile unsigned int young;
extern volatile _mch kmemory;
/*
inline _mlock& _mlock::operator=(_mlock& source)
{
	lnow = source.lnow;
	waiting = source.waiting;
	state = source.state;
}
*/
#define SHOULD_HAVE_USER			(~0)//unlock 
#define DEAD_LOCK_CLEARED			((~0) >> 1)

#define CLEAR_DEAD_LOCK(x,y)		do		\
    {							\
      ring* pointer = run;				\
      while(pointer != run)				\
	{						\
	  if((pointer) == ((_mlock*)x)->lnow)		\
	    break;					\
	  pointer = pointer->next;			\
	}						\
      if(pointer == ((_mlock*)x)->lnow)			\
	{						\
	  ((_mlock*)x)->lnow = SHOULD_HAVE_USER;	\
	}						\
    }while(0);



inline _mlock* MUTEX_Init(_mlock* locker)
{
  locker->lnow = NULL;
  locker->waiting = NULL;
  locker->state = 0;
  return locker;
}

inline ring* MUTEX_MustLock(_mlock* locker,ring* owner)
{
  ring _backring;
  ring* backring = RingInit(&_backring,owner->content);
  ring* nowring = (ring*)run;
  run = backring;

  locker->state |= IN_NEED;
  while(!MUTEX_TryToLock(locker,owner))
    {
      
      RingInsert(backring,(ring*)(locker->lnow));
      KernelSchedule(SCHEDULE_DEFAULT);
      
    }
  
  run = nowring;
  ring* ret = (backring->next == backring?NULL:backring->next);

  RingRemove(backring);
  locker->state &= ~IN_NEED;
  return ret;
    
} 

void MUTEX_Lock(_mlock* locker,ring* owner)
{


  //Danger Area:Just stop threading
  if(locker->lnow == NULL)
    {
      locker->lnow = owner;
      //Danger Area out:Just start threading
      return;
    }
  //Danger Area out:Just start threading

  //Check dead-lock
  //		CLEAR_DEAD_LOCK(locker);
  /*	if(locker->lnow == SHOULD_HAVE_USER)
	{//dead-lock cleared
	if(locker->waiting != NULL)
	{//Activate waiting & push to waiting
	slnode* pt = locker->waiting;
	locker->lnow = pt->mark;
	locker->waiting = locker->waiting->next;
	RingInsert(run,pt->mark);
	slnode* newpt = locker->waiting;
	while(newpt->next != NULL)
	newpt = newpt->next;
	pt->mark = owner;
	InsertSListNode(newpt,pt);
				
	if(run == owner)
	MUTEX_ThreadTurning();
	else
	{
	RingRemove(owner);	
	//				ThreadTurning();
	}
	}
	else
	{
	locker->lnow = owner;
	return;
	}
	}
	else*/
  {//push to waiting
    slnode* pt = (slnode*)_KHEAPAPPLY(sizeof(slnode));
    MakeSListNode(pt,owner);
    slnode* newpt = locker->waiting;
    //Danger Area:Just stop threading
    if(locker->waiting == NULL)
      {
	locker->waiting = newpt;
      }
    else
      {
	while(newpt->next != NULL)
	  newpt = newpt->next;
	InsertSListNode(newpt,pt);
      }
    //Danger Area out:Just start threading
    if(run == owner)
      {
	KernelSchedule(SCHEDULE_MUTEX);
      }
    else
      {
	RingRemove(owner);	
	//				ThreadTurning();
      }	
  }
		
	
}

int MUTEX_TryToLock(_mlock* locker,ring* owner)
{
  //Danger Area
  if(locker->lnow == NULL)
    {
      locker->lnow = owner;
      //Danger Out
      return 1;
    }
  //Danger out
  //Check dead-lock
  //		CLEAR_DEAD_LOCK(locker);
  /*	if(locker->lnow == SHOULD_HAVE_USER)
	{//dead-lock cleared
	if(locker->waiting != NULL)
	{//Activate waiting & return 0;
	slnode* pt = locker->waiting;
	locker->lnow = pt->mark;
	locker->waiting = locker->waiting->next;
	RingInsert(run,pt->mark);
	_KHEAPRELEA(pt);
	}
	else
	{
	locker->lnow = owner;
	return 1;
	}
	}*/
  return 0;
}

int MUTEX_UnLock(_mlock* locker,ring* owner)
{
  int ret = 0;
  if(locker->lnow == owner)
    {//unlock it
      ret = 1;
      locker->lnow = (void*)SHOULD_HAVE_USER;
      if(locker->waiting != NULL)
	{//Activate Waiting
	  slnode* pt = locker->waiting;
	  locker->lnow = pt->mark;
	  locker->waiting = locker->waiting->next;
	  RingInsert((ring*)run,(ring*)(pt->mark));
	  _KHEAPRELEA(pt);
	}
      else
	locker->lnow = NULL;
      while(locker->state & IN_NEED)
	KernelSchedule(SCHEDULE_DEFAULT);
    }
  return ret;
}



int KERNEL_MUTEX_Lock(_klock* locker,ring* owner)
{
  //Just Stop threading
  if(locker->lnow == NULL)
    {
      locker->lnow = owner;
      //Just Start threading
      return 1;
    }
  //Just Start threading
  //Check dead-lock
  //		CLEAR_DEAD_LOCK(locker);
  /*	if(locker->lnow == SHOULD_HAVE_USER)
	{//dead-lock cleared
	if(locker->waiting != NULL)
	{//Activate waiting & push to waiting
	ring* pt;
	QueuePop(locker,&pt);
	RingInsert(run,pt);
	QueuePush(locker,&owner);
				
	if(run == owner)
	MUTEX_ThreadTurning();
	else
	{
	RingRemove(owner);	
	//				ThreadTurning();
	}
	}
	else
	{
	locker->lnow = owner;
	return;
	}
	}
	else*/
  {//push to waiting

    //Just Stop threading		
    QueuePush(&(locker->waiting),&owner);
    //Just Start threading
    if(run == owner)
      {
	KernelSchedule(SCHEDULE_MUTEX);
      }
    else
      {
	RingRemove(owner);	
	//				ThreadTurning();
      }	
  }
}
int KERNEL_MUTEX_UnLock(_klock* locker,ring* owner)
{
  if(locker->lnow == owner)
    {//unlock it
      locker->lnow = (void*)SHOULD_HAVE_USER;
      if(!QueueEmpty(&(locker->waiting)))
	{//Activate Waiting
	  ring* pt;
	  QueuePop(&(locker->waiting),&pt);
	  RingInsert((ring*)run,pt);
	}
      else
	locker->lnow = NULL;
    }
}
